﻿using System;
using System.Linq;
using System.Text;
using MongoDB.Bson;
using MongoDB.Driver;
using System.Windows;
using System.Reflection;
using System.Threading.Tasks;
using FrameWork.Data.Mapping;
using System.Linq.Expressions;
using System.Collections.Generic;
using MongoDB.Bson.Serialization;
using Microsoft.IdentityModel.Logging;
using System.Drawing.Printing;

namespace FrameWork.Data.MongoDb
{
    public class MongoHelper
    {
        #region ___字段___

        /// <summary>
        /// 数据库名称
        /// </summary>
        private string dbName = "runoob";

        /// <summary>
        /// 连接客户端
        /// </summary>
        private static IMongoClient client;
        public  static IMongoClient Client=>client;

        /// <summary>
        /// 连接数据库
        /// </summary>
        private static IMongoDatabase db;

        /// <summary>
        /// 集合名称
        /// </summary>
        public string collName = "";

        /// <summary>
        /// 变量锁
        /// </summary>
        private readonly object lockHelper = new object();

        /// <summary>
        /// 服务器网址
        /// </summary>
        private string connStr = "mongodb://127.0.0.1:27017";

        //private string connStr = "mongodb://192.168.8.141:27017";

        #endregion ___字段___

        #region ___构造函数___

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="connStr"></param>
        /// <param name="dbName"></param>
        /// <param name="collName"></param>
        public MongoHelper()
        {
        }

        #endregion ___构造函数___

        #region ___写入___

        /// <summary>
        /// 从计数器中获取自增长ID
        /// </summary>
        /// <param name="collName">集合名</param>
        /// <returns></returns>
        public int GetNextId(string collName)
        {
            var collection = db.GetCollection<BsonDocument>("IdGeneratorCounters");
            var filter = Builders<BsonDocument>.Filter.Eq("_id", collName);
            var update = Builders<BsonDocument>.Update.Inc("seq", 1);
            var options = new FindOneAndUpdateOptions<BsonDocument, BsonDocument>()
            {
                IsUpsert = true,
                ReturnDocument = ReturnDocument.After
            };
            var result = collection.FindOneAndUpdate(filter, update, options);
            return result["seq"].AsInt32;
        }

        /// <summary>
        /// 插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="document"></param>
        /// <param name="collName"></param>
        public void Insert<T>(T document)
        {
            this.GetCollection<T>().InsertOne(document);
        }

        /// <summary>
        /// 插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="document"></param>
        /// <param name="collName"></param>
        public void Insert<T>(string collName, T document)
        {
            var collection = db.GetCollection<T>(collName);
            collection.InsertOne(document);
        }

        /// <summary>
        /// 异步插入对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="document"></param>
        public async void InsertAsync<T>(T document)
        {
            await this.GetCollection<T>().InsertOneAsync(document);
        }

        /// <summary>
        /// 批量插入
        /// </summary>
        /// <param name="dicInfo"></param>
        public void InsertMany<T>(IEnumerable<T> documents)
        {
            this.GetCollection<T>().InsertMany(documents);
        }

        /// <summary>
        /// 异步批量插入
        /// </summary>
        /// <param name="dicInfo"></param>
        public async void InsertManyAsync<T>(IEnumerable<T> documents)
        {
            await this.GetCollection<T>().InsertManyAsync(documents);
        }

        /// <summary>
        /// 批量插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collName"></param>
        /// <param name="documents"></param>
        public void InsertMany<T>(string collName, IEnumerable<T> documents)
        {
            var collection = db.GetCollection<T>(collName);
            collection.InsertMany(documents);
        }

        /// <summary>
        /// 根据主键更新或插入记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <param name="document"></param>
        /// <returns></returns>
        public long InsertOrUpdateById<T>(string doclName, int id, T document)
        {
            var collection = db.GetCollection<T>(doclName);
            var filter = Builders<T>.Filter.Eq("_id", id);
            var result = collection.ReplaceOne(filter, document, new ReplaceOptions { IsUpsert = true });
            //result.ModifiedCount== 0 执行了插入操作，否则执行了更新操作
            return result.ModifiedCount;
        }

        #endregion ___写入___

        #region ___查询___

        /// <summary>
        /// 按名称进行查询
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public List<T> QueryByColName<T>(object colValue, string colName = "Name")
        {
            var rest = this.GetCollection<T>().Find(Builders<T>.Filter.Eq(colName, colValue));
            return rest.As<T>().ToList();
        }

        /// <summary>
        /// 按名称s进行查询
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public List<T> QueryByColNames<T>(string CollectionName, Expression<Func<T, bool>> func)
        {
            try
            {
                var rest = db.GetCollection<T>(CollectionName).Find(func);
                return rest.As<T>().ToList();
            }
            catch (Exception ex)
            {
                throw ex;
                return default;
            }
        }

        /// <summary>
        /// 只查询一条
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public T QueryOne<T>(string Id)
        {
            var rest = this.GetCollection<T>().Find(Builders<T>.Filter.Eq("Id", Id)).Limit(1);
            var r = rest.As<T>().ToList();
            return r.Count > 0 ? r[0] : default(T);
        }

        /// <summary>
        /// 查询最后一条记录
        /// </summary>
        /// <typeparam name="TProperty"></typeparam>
        /// <param name="collectionName"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public T QueryOne<T>(string collName, string propertyName)
        {
            var sort = Builders<T>.Sort.Descending(propertyName);
            return this.GetCollection<T>().Find(_ => true).Sort(sort).Limit(1).FirstOrDefault();
        }

        /// <summary>
        /// 无条件查询，即返回全部
        /// </summary>
        /// <returns></returns>
        public List<T> QueryAll<T>()
        {
            var collection = db.GetCollection<BsonDocument>(string.IsNullOrEmpty(collName) ? typeof(T).Name : collName);
            var rest = collection.Find(Builders<BsonDocument>.Filter.Empty);
            return rest.As<T>().ToList();
        }

        /// <summary>
        /// 根据条件筛选列表
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public List<T> ListByCondition<T>(Expression<Func<T, bool>> func)
        {
            return this.GetCollection<T>().Find(func).ToList<T>();
        }

        /// <summary>
        /// 获取列表
        /// </summary>
        /// <param name="func"></param>
        /// <param name="count">数量</param>
        /// <returns></returns>
        public List<T> ListByCondition<T>(Expression<Func<T, bool>> func, int count)
        {
            return this.GetCollection<T>().Find(func).Limit(count).ToList();
        }

        /// <summary>
        /// 获取分页列表
        /// </summary>
        /// <param name="func"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <param name="record"></param>
        /// <param name="sort"></param>
        /// <returns></returns>
        public List<T> ListPage<T>(Expression<Func<T, bool>> func, int page, int pageSize, ref long recordCount, SortDefinition<T> sort = null)
        {
            if (null == sort)
            {
                sort = new ObjectSortDefinition<T>(new { });
                sort.Ascending("Id");
            }
            recordCount = this.GetCollection<T>().CountDocuments<T>(func);
            return this.GetCollection<T>().Find(func).Sort(sort).Skip((page - 1) * pageSize).Limit(pageSize).ToList();
        }

        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="page"></param>
        /// <param name="pageSize"></param>
        /// <param name="recordCount"></param>
        /// <param name="sort"></param>
        /// <returns></returns>
        public List<T> ListPageColName<T>(Expression<Func<T, bool>> filter, int page, int pageSize, ref long recordCount, SortDefinition<T> sort = null)
        {
            if (null == sort)
            {
                sort = new ObjectSortDefinition<T>(new { });
                sort.Ascending("Id");
            }
            IMongoCollection<T> collection = db.GetCollection<T>(string.IsNullOrEmpty(collName) ? typeof(T).Name : collName);
            recordCount = collection.CountDocuments<T>(filter);
            return collection.Find(filter, null).Sort(sort).Skip((page - 1) * pageSize).Limit(pageSize).ToList();
        }

        /// <summary>
        /// 多条件查询，根据条件，通过反射从document中获取属性的值,属性和值作为查询条件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collName">集合名</param>
        /// <param name="document">文档</param>
        /// <param name="where">查询条件为T的属性英文,作为分割符""</param>
        /// <returns></returns>
        public List<T> QueryByWhere<T>(string collName, T document, string where)
        {
            //查询过滤器
            var filterBuilder = Builders<T>.Filter;
            var filters = new List<FilterDefinition<T>>();
            //通过反射从document中获取属性的值,属性和值作为查询条件
            Type objectType = typeof(T);
            string[] propertyNames = where.Split(',');
            foreach (string propertyName in propertyNames)
            {
                string fieldName = propertyName.Trim();
                if (string.IsNullOrEmpty(fieldName))
                {
                    continue;
                }
                PropertyInfo property = objectType.GetProperty(fieldName);
                if (property == null)
                {
                    continue;
                }
                object value = property.GetValue(document);

                var filter = filterBuilder.Eq(propertyName, value);
                filters.Add(filter);
            }
            //根据过滤器查询数据
            var combinedFilter = filterBuilder.And(filters);
            var collection = db.GetCollection<T>(collName);
            var result = collection.Find(combinedFilter).ToList();
            return result;
        }

        /// <summary>
        /// 查询属性的最大值
        /// 使用例如:查询TestEventData集合中ID的最大值: GetMaxPropertyValue<int>("TestEventData", "Id");
        /// </summary>
        /// <typeparam name="TProperty"></typeparam>
        /// <param name="collectionName"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public TProperty GetMaxPropertyValue<TProperty>(string collectionName, string propertyName)
        {
            var collection = db.GetCollection<BsonDocument>(collectionName);
            var sort = Builders<BsonDocument>.Sort.Descending(propertyName);
            var projection = Builders<BsonDocument>.Projection.Include(propertyName);
            var options = new FindOptions<BsonDocument, TProperty>
            {
                Sort = sort,
                Projection = projection,
                Limit = 1
            };
            return collection.FindSync(FilterDefinition<BsonDocument>.Empty, options).FirstOrDefault();
        }

        #endregion ___查询___

        #region ___更新___

        /// <summary>
        /// 根据ID更新一条记录
        /// </summary>
        /// <param name="id"></param>
        /// <param name="field"></param>
        /// <param name="value"></param>
        public void Update<T>(string id, string field, string value)
        {
            var filter = Builders<T>.Filter.Eq("Id", id);
            var updated = Builders<T>.Update.Set(field, value);
            UpdateResult result = GetCollection<T>().UpdateOneAsync(filter, updated).Result;
        }
       public void Update<T>(string doclName,  string id, string field, string value)
        {
            var collection = db.GetCollection<T>(doclName);
            var filter = Builders<T>.Filter.Eq("Id", id);
            var updated = Builders<T>.Update.Set(field, value);
            UpdateResult result = GetCollection<T>().UpdateOneAsync(filter, updated).Result;
        }
    


        /// <summary>
        /// 根据ID更新一条记录
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="id"></param>
        public void Update<T>(T entity, string id) where T : ModelBase
        {
            Update(entity, a => a.Id.Equals(id));
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="id"></param>
        public void UpdateByFunc<T>(T entity, Expression<Func<T, bool>> func, string collName = "") where T : ModelBase
        {
            Update(entity, func, collName);
        }

        /// <summary>
        /// 根据条件更新一条记录
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="func"></param>
        private void Update<T>(T entity, Expression<Func<T, bool>> func, string collName = "")
        {
            var old = GetEntity(func);
            foreach (var prop in entity.GetType().GetProperties())
            {
                if (prop.Name.Equals("Id"))
                    continue;
                var newValue = prop.GetValue(entity);
                var oldValue = old.GetType().GetProperty(prop.Name).GetValue(old);
                if (newValue != null)
                {
                    if (!newValue.ToString().Equals(oldValue.ToString()))
                    {
                        old.GetType().GetProperty(prop.Name).SetValue(old, newValue);
                    }
                }
            }
            if (string.IsNullOrEmpty(collName))
                GetCollection<T>().ReplaceOne(func, old);
            else
            {
                var collection = db.GetCollection<T>(collName);
                collection.ReplaceOne(func, old);
            }
        }

        /// <summary>
        /// 根据主键更新记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <param name="document"></param>
        /// <returns></returns>
        public async Task<ReplaceOneResult> ReplaceOneAsync<T>(string id, T document)
        {
            var filter = Builders<T>.Filter.Eq("_id", id);
            return await GetCollection<T>().ReplaceOneAsync(filter, document);
        }

        #endregion ___更新___

        #region ___删除___

        /// <summary>
        /// 异步根据主键删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<DeleteResult> DeleteByIdAsync<T>(string id)
        {
            var filter = Builders<T>.Filter.Eq("_id", id);
            return await GetCollection<T>().DeleteOneAsync(filter);
        }

        /// <summary>
        /// 根据条件删除数据
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public long Delete<T>(Expression<Func<T, bool>> func)
        {
            return GetCollection<T>().DeleteMany(func).DeletedCount;
        }

        /// <summary>
        /// 异步全量删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public async Task<DeleteResult> DeleteAllAsync<T>()
        {
            return await GetCollection<T>().DeleteManyAsync(_ => true);
        }

        /// <summary>
        /// 全量删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public void DeleteAll<T>()
        {
            GetCollection<T>().DeleteMany(_ => true);
        }

        #endregion ___删除___

        #region ___私有方法___

        /// <summary>
        /// 初始化连接客户端
        /// </summary>
        public MongoHelper CreateDB(string pconnStr = "", string pdbName = "")
        {
            if (db == null)
            {
                lock (lockHelper)
                {
                    if (db == null)
                    {
                        client = new MongoClient(string.IsNullOrEmpty(pconnStr) ? connStr : pconnStr);
                        db = client.GetDatabase(string.IsNullOrEmpty(pdbName) ? dbName : pdbName);
                    }
                }
            }
            return this;
        }

        /// <summary>
        /// 根据ID获取对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        private T GetEntity<T>(Expression<Func<T, bool>> func)
        {
            return GetCollection<T>().Find(func).FirstOrDefault();
        }

        /// <summary>
        /// 获取表名
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private IMongoCollection<T> GetCollection<T>()
        {
            return db.GetCollection<T>(string.IsNullOrEmpty(collName) ? typeof(T).Name : collName);
        }

        #endregion ___私有方法___
    }
}